﻿using System.Collections.Generic;
using System.Linq;

namespace CarArranger.Model
{
    public class Yard
    {
        public List<Track> Tracks { get; set; } = new List<Track>();
        /// <summary>
        /// 是否右端作业，true = 右端作业， false = 左端作业
        /// </summary>
        public bool IsLeftHandWork { get; set; }
    }

    /// <summary>
    /// 股道
    /// </summary>
    public class Track
    {
        public Track(string name)
        {
            Name = name;
        }
        /// <summary>
        /// 股道名称
        /// </summary>
        public string Name { get; }
    }

    /// <summary>
    /// 车组
    /// </summary>
    public class CarGroup
    {
        /// <summary>
        /// 目的地编号
        /// </summary>
        public int DestNum { get; set; }
        /// <summary>
        /// 车辆数
        /// </summary>
        public int CarNum { get; set; }

        public override string ToString()
        {
            return $"{DestNum}_{CarNum}";
        }
    }

    /// <summary>
    /// 车列
    /// </summary>
    public class CarList : List<CarGroup> 
    { 
        /// <summary>
        /// 初始位置
        /// </summary>
        public Track PrimalTrack { get; set; }
    }


    public enum MovementType
    {
        Drop = 0, //溜放
        Pick = 1  //连挂
    }
    public static class Extension
    {
        public static MovementType Reverse(this MovementType t)
        {
            if (t == MovementType.Drop)
            {
                return MovementType.Pick;
            }
            else
            {
                return MovementType.Drop;
            }
        }
    }
    public struct Movement
    {
        public Track Track { get; set; }
        public MovementType MType { get; set; }
        public int CarGroupNum { get; set; }

        public override string ToString()
        {
            string s = MType == MovementType.Drop ? "-" : "+";
            return $"{Track.Name} {s} {CarGroupNum}";
        }
    }

    /// <summary>
    /// 调车作业计划
    /// </summary>
    public class MovePlan
    {
        public List<Movement> Movements { get; set; } = new List<Movement>();

        /// <summary>
        /// 调车钩数
        /// </summary>
        public int MoveCount
        {
            get
            {
                return Movements.Count();
            }
        }

        /// <summary>
        /// 调车程数
        /// </summary>
        public int MoveLength
        {
            get
            {
                return MoveCount + Movements.Where(i => i.MType == MovementType.Pick).Count();
            }
        }
    }

    public class Document
    {
        public Yard Yard { get; set; }
        public CarList CarList { get; set; }

        //已执行钩计划
        public MovePlan Plan { get; set; }

        /// <summary>
        /// 股道状态
        /// </summary>
        public Dictionary<Track, Deque<CarGroup>> TrackStatus { get; set; }
        /// <summary>
        /// 调车线状态
        /// </summary>
        public Deque<CarGroup> TransferTrackStatus { get; set; }

        /// <summary>
        /// 初始化
        /// </summary>
        public void InitStatus()
        {
            //初始化状态
            TrackStatus = new Dictionary<Track, Deque<CarGroup>>();
            foreach (Track track in Yard.Tracks)
            {
                TrackStatus.Add(track, new Deque<CarGroup>());
            }
            TransferTrackStatus = new Deque<CarGroup>();

            //加入
            if(CarList != null)
            {
                TrackStatus[CarList.PrimalTrack].AddBackRange(CarList.ToArray());
            }

            Plan = new MovePlan();
        }

        public bool ApplyMovement(Movement mov)
        {
            if (mov.Track == null) return false;
            if (mov.MType == MovementType.Drop && TransferTrackStatus.Count() < mov.CarGroupNum) return false;
            if (mov.MType == MovementType.Pick && TrackStatus[mov.Track].Count() < mov.CarGroupNum) return false;
            
            if (mov.MType == MovementType.Drop)
            {
                for (int i = 1; i <= mov.CarGroupNum; i++)
                {
                    if (Yard.IsLeftHandWork)
                    {
                        CarGroup temp = TransferTrackStatus.RemoveBack();
                        TrackStatus[mov.Track].AddFront(temp);
                    }
                    else
                    {
                        CarGroup temp = TransferTrackStatus.RemoveFront();
                        TrackStatus[mov.Track].AddBack(temp);
                    }
                }
            }
            else
            {
                for (int i = 1; i <= mov.CarGroupNum; i++)
                {
                    if (Yard.IsLeftHandWork)
                    {
                        CarGroup temp = TrackStatus[mov.Track].RemoveFront();
                        TransferTrackStatus.AddBack(temp);
                    }
                    else
                    {
                        CarGroup temp = TrackStatus[mov.Track].RemoveBack();
                        TransferTrackStatus.AddFront(temp);
                    }
                }
            }

            return true;
        }
    }
}
